//==============================================================================
// Copyright (c) 2008-2013 Niall Ryan. All Rights Reserved.
//==============================================================================

#ifndef HYDRA_THREAD_H
#define HYDRA_THREAD_H 1

#include "internal/thread_internal.h"

namespace Hydra
{
	class Thread
	{
	public:
		Thread() : m_handle(0), m_id(0), m_invoker(NULL) { }

		template<typename F>
		Thread(F function) : m_handle(0), m_id(0)
		{
			m_invoker = new Internal::ThreadInvoker0<F>(function);
		}

		template<typename F, typename X>
		Thread(F function, X x) : m_handle(0), m_id(0)
		{
			m_invoker = new Internal::ThreadInvoker1<F,X>(function, x);
		}

		template<typename F, typename X, typename Y>
		Thread(F function, X x, Y y) : m_handle(0), m_id(0)
		{
			m_invoker = new Internal::ThreadInvoker2<F,X,Y>(function, x, y);
		}

		~Thread()
		{
			if( m_handle )
				CloseHandle(m_handle);
		}

		void Start()
		{
			if( !m_handle )
				m_handle = (HANDLE)_beginthreadex(NULL, 0, &ThreadFunc, this, 0, &m_id);
		}

		void Join()
		{
			if( m_handle )
				WaitForSingleObject(m_handle, INFINITE);
		}

	private:
		static unsigned int __stdcall ThreadFunc(void* arg)
		{
			Thread* thread = static_cast<Thread*>(arg);
			thread->m_invoker->Invoke();
			_endthreadex(0);
			return 0;
		}

		Internal::ThreadInvokerBase* m_invoker;
		unsigned int m_id;
		HANDLE m_handle;
	};

	namespace this_thread
	{
		inline unsigned int get_id()				{ return Internal::threadGetId(); }
		inline void sleep(unsigned int duration)	{ Internal::threadSleep(duration); }
		inline void yield()							{ Internal::threadYield(); }
		inline void pause(unsigned int loops)		{ Internal::threadPause(loops); }
	}
}

#endif
